<?php
/**
 * Created by b17
 * 2/9/12 8:13 PM
 */

namespace Managers;

class Users extends BaseManager
{
    const TABLE = '\Catalog\Users';

    protected $__table = self::TABLE;

    private $_cookieDelimiter = '.';

    private $_defaultParams;

    /**
     * Глобальное сало (подгружается с конфига).
     * @var string
     */
    protected $salt;

    public function __construct()
    {
        parent::__construct();
        $this->salt = \Zend_Registry::get('config')->crypto->salt;
        $this->_defaultParams = \Zend_Registry::get('config')->user;
    }

    /**
     * Авентифицирует пользователя по email/password.
     *
     * @param $email
     * @param $password
     * @return bool|\Catalog\Users|object
     */
    public function auth($email, $password)
    {
        $res = $this->createQueryBuilder()
            ->andWhere('u.email = :email')->setParameter('email', $email)
            ->getQuery()->getArrayResult();
        $user = count($res) ? $res[0] : false;

        if ($user) {
            $this->_throwIfLocked($user);
            $cred = $this->encryptPassword($password, $user['salt']);
            if ($cred == $user['password']) {
                $this->doManualAuth($user);
                return $user;
            }
        }
        return false;
    }

    /**
     * Создает нового пользователя.
     *
     * @param array $values
     */
    public function create(array $values)
    {
        $entity = new \Catalog\Users();
        $this->_setEntityValues($entity, $values);
        $this->_em->persist($entity);
        $this->flush();
    }

    private function _setEntityValues(\Catalog\Users $entity, array $values)
    {
        $salt = $this->getSalt();
        $entity->setIsDel(false);
        $entity->setIsAdmin(false);
        $entity->setEmail($values['email']);
        $entity->setSalt($salt);
        $entity->setIsLocked(false);
        $entity->setPassword($this->encryptPassword($values['password'], $salt));
        $entity->setName($values['name']);
        $entity->setMoney((int)$this->_defaultParams->money);
    }

    /**
     * Возвращает случайное сало.
     *
     * @return string
     */
    private function getSalt()
    {
        return sha1(microtime(true) . $this->salt);
    }

    /**
     * Возвращает пользователя с заданным ID.
     * Если пользователь не найден, возвращает false.
     *
     * @param $id
     * @return bool|array
     */
    public function getById($id)
    {
        $qb = $this->createQueryBuilder()
            ->andWhere('u.id = :id')->setParameter('id', $id);
        $res = $qb->getQuery()->getArrayResult();
        return count($res) ? $res[0] : false;
    }

    /**
     * Создает конструктор запросов для пользователей.
     *
     * @return \Doctrine\ORM\QueryBuilder
     */
    protected function createQueryBuilder()
    {
        $qb = $this->_em->createQueryBuilder()
            ->select('u')
            ->from($this->__table, 'u')
            ->andWhere('u.isDel = 0');

        return $qb;
    }

    /**
     * Возвращает хеш пароля.
     *
     * @param $password
     * @param $salt
     * @return string
     */
    private function encryptPassword($password, $salt)
    {
        return sha1($password . $this->salt . $salt);
    }

    /**
     * Записываем параметры пользователя в Zend_Auth объект.
     *
     * @static
     * @param array $user
     */
    public static function doManualAuth(array $user)
    {
        \Zend_Auth::getInstance()->getStorage()->write($user);
    }

    public function getCookieData($user)
    {
        $data = array();
        $data[] = $user['id'];
        $data[] = $this->encryptPassword($user['email'], $user['salt']);
        return join($this->_cookieDelimiter, $data);
    }

    public function cookieAuth($cookie)
    {
        $params = explode($this->_cookieDelimiter, $cookie);
        if (count($params) != 2) {
            return false;
        }
        list($id, $sign) = $params;
        $user = $this->getById($id);
        if (!$user) {
            return false;
        }

        if ($sign == $this->encryptPassword($user['email'], $user['salt'])) {
            $this->doManualAuth($user);
            return true;
        }

        return false;
    }

    public function increaseMoney($userId, $moneyCount)
    {
        $entity = $this->find($userId);
        /* @var \Catalog\Users $entity */
        $entity->setMoney($entity->getMoney() + $moneyCount);
        $this->_em->persist($entity);
        $this->flush();
        return $entity;
    }

    public function getByOpenId($openId)
    {
        $qb = $this->createQueryBuilder()
            ->andWhere('u.openId = :openId')->setParameter('openId', $openId);
        $res = $qb->getQuery()->getArrayResult();

        return count($res) ? $res[0] : false;
    }

    public function authByOpenId(\TBS\Auth\Identity\Generic $identity)
    {
        $user = $this->getByOpenId($identity->getId());
        $this->_throwIfLocked($user);
        if (!$user) {
            $entity = $this->_registerByOpenId($identity);
            $user = $this->getById($entity->getId());
        }
        $this->doManualAuth($user);
        return $user;
    }

    private function _throwIfLocked($user)
    {
        if ($user['isLocked']) {
            throw new \LogicException("Пользователь заблокирован. Приносим свои извинения.");
        }
    }

    private function _registerByOpenId(\TBS\Auth\Identity\Generic $identity)
    {
        $entity = new \Catalog\Users();

        $values['password'] = mt_rand() . $this->salt; // случайный пароль
        $values['email'] = "openid@{$identity->getName()}";
        $data = $identity->getApi()->getProfile();
        $values['name'] = $data['name'];

        $this->_setEntityValues($entity, $values);

        $entity->setOpenId($identity->getId());

        $this->_em->persist($entity);
        $this->flush();
        return $entity;
    }

    public function getList($offset = null, $limit = null)
    {
        $qb = $this->createQueryBuilder()
            ->addOrderBy('u.id', 'DESC');
        $this->_setLimit($qb, $limit, $offset);
        $res = $qb->getQuery()->getArrayResult();
        return $res;
    }

    public function changeLockFlag($id)
    {
        $entity = $this->find($id);
        /* @var \Catalog\Users $entity */
        $entity->setIsLocked(!$entity->getIsLocked());
        $this->_em->persist($entity);
        $this->flush();
        return $entity;
    }
}
